#include "msgheader.h"
#include "cJSON.h"
#include "MQTTClient.h"
#include "shmem.h"
#include "msg_queue_peer.h"

//共享内存相关变量
static struct shm_param para;     //存放共享内存的参数
static int *total;                //指向共享内存中数据节点总个数
static struct std_node *node_arr; //指向共享内存中节点缓存数组头

//MQTT相关变量
volatile MQTTClient_deliveryToken deliveredtoken;
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;

//消息队列相关变量
struct msgbuf send_buf; //消息队列结构体

//点表文件读取相关变量
static int send_mode = 1;     //消息上报模式
static int send_interval = 5; //消息上报间隔时间

//关闭标志
char closekongtiao[256] = {"{\"key\":19,\"name\":\"close\",\"type\":1,\"dev_type\":1,\"val\":1}"};

//函数声明
void delivered(void *context, MQTTClient_deliveryToken dt);
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message);
void connlost(void *context, char *cause);
int mqtt_client_to_server();
int point_init();
int judge_device(char *buf);
void *handler(void *arg);
char *shared_to_char(struct std_node *tmp);
void send_all_shared_memory();
void send_variation_shared_memory();
int send_shared_memory();

int main(int argc, char const *argv[])
{
    printf("server is go\n");

    //初始化共享内存
    int ret = -1;
    ret = shm_init(&para, "shm_test", MAX_NODE_SIZE);
    if (ret == -1)
    {
        return -1;
    }

    //映射共享内存
    void *node_p = shm_getaddr(&para);
    if (node_p == NULL)
    {
        return -1;
    }

    //清空共享内存
    memset(node_p, 0, MAX_NODE_SIZE);

    //通过偏移量,total指向共享内存首地址,里面存放数据个数
    //node_arr指向后面数据的收地址
    total = (int *)node_p;
    node_arr = (struct std_node *)(node_p + sizeof(int));

    //初始化点表
    if (point_init() < 0)
    {
        perror("point_init err");
        return -1;
    }

    //创建发送消息线程（发送线程内自动创建接受线程）
    pthread_t mqtt_tid;
    if (pthread_create(&mqtt_tid, NULL, handler, NULL))
    {
        perror("create err");
        return -1;
    }

    pthread_detach(mqtt_tid);
    while (1)
        ;

    return 0;
}

void delivered(void *context, MQTTClient_deliveryToken dt)
{
    deliveredtoken = dt;
}

//MQTT接收消息函数
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    printf("进入接收函数---------%d\n", __LINE__);
    send_buf.mtype = judge_device((char *)message->payload);
    if (send_buf.mtype == -1)
    {
        printf("judge_device to mtype err\n");
        return -1;
    }
    else if (send_buf.mtype == 1 || send_buf.mtype == 2 || send_buf.mtype == 3)
    {
        strcpy(send_buf.mdata, (char *)message->payload);
        if (msg_queue_send("topic", &send_buf, sizeof(send_buf), 0) < 0)
        {
            printf("meg_queue_send error\n");
            return -1;
        }
    }

    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}

void connlost(void *context, char *cause)
{
    printf("\nConnection lost\n");
    printf("     cause: %s\n", cause);
}

int mqtt_client_to_server()
{
    //进入发送函数
    printf("进入发送函数\n-----------%d\n", __LINE__);
    int rc;
    int ch;
    char buf[1024];
    MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;

    MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);

    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        exit(EXIT_FAILURE);
    }

    MQTTClient_subscribe(client, TOPICDOWN, QOS);

    do
    {
        send_shared_memory();
    } while (1);

    MQTTClient_unsubscribe(client, TOPICDOWN);
    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);

    return 1;
}

//初始化点表到共享内存
int point_init()
{
    static int num = 0;
    FILE *file = fopen("/mnt/config/JSONdata.json", "r");
    if (NULL == file)
    {
        perror("fopen JSONdata.json err");
        return -1;
    }

    // 动态分配内存
    char *buf = (char *)malloc(2048);
    if (buf == NULL)
    {
        perror("malloc err");
        return -1;
    }

    size_t jread = fread(buf, 1, 2048, file);
    if (jread < 0)
    {
        perror("fread err");
        free(buf); // 读取失败时释放内存
        return -1;
    }

    fclose(file);

    cJSON *root = cJSON_Parse(buf);
    if (root == NULL)
    {
        printf("parse err\n");
        return -1;
    }

    cJSON *stm32 = cJSON_GetObjectItem(root, "stm32");
    cJSON *sdata = cJSON_GetObjectItem(stm32, "data");
    int size = cJSON_GetArraySize(sdata);

    for (int i = 0; i < size; i++)
    {
        cJSON *tmp = cJSON_GetArrayItem(sdata, i);
        cJSON *key = cJSON_GetObjectItem(tmp, "key");
        cJSON *name = cJSON_GetObjectItem(tmp, "name");
        cJSON *type = cJSON_GetObjectItem(tmp, "type");

        num++;
        node_arr[num - 1].key = key->valueint;
        strcpy(node_arr[num - 1].name, name->valuestring);
        node_arr[num - 1].type = type->valueint;
        node_arr[num - 1].dev_type = 1;
        if (node_arr[num - 1].type == 1)
        {
            node_arr[num - 1].old_val.a_val = 0;
            node_arr[num - 1].new_val.a_val = 0;
        }
        else if (node_arr[num - 1].type == 2)
        {
            node_arr[num - 1].old_val.b_val = 0;
            node_arr[num - 1].new_val.b_val = 0;
        }
        else if (node_arr[num - 1].type == 3)
        {
            node_arr[num - 1].old_val.c_val = 0;
            node_arr[num - 1].new_val.c_val = 0;
        }
        node_arr[num - 1].ret = 0;
        char *node = shared_to_char(&node_arr[num - 1]);
        printf("%s\n", node);
    }
    printf("STM32 OK\n--------------%d\n", __LINE__);

    cJSON *modbus = cJSON_GetObjectItem(root, "modbus");
    cJSON *mdata = cJSON_GetObjectItem(modbus, "data");
    size = cJSON_GetArraySize(mdata);
    for (size_t i = 0; i < size; i++)
    {
        cJSON *tmp = cJSON_GetArrayItem(mdata, i);
        cJSON *key = cJSON_GetObjectItem(tmp, "key");
        cJSON *name = cJSON_GetObjectItem(tmp, "name");
        cJSON *type = cJSON_GetObjectItem(tmp, "type");

        num++;
        node_arr[num - 1].key = key->valueint;
        strcpy(node_arr[num - 1].name, name->valuestring);
        node_arr[num - 1].type = type->valueint;
        node_arr[num - 1].dev_type = 2;
        if (node_arr[num - 1].type == 1)
        {
            node_arr[num - 1].old_val.a_val = 0;
            node_arr[num - 1].new_val.a_val = 0;
        }
        else if (node_arr[num - 1].type == 2)
        {
            node_arr[num - 1].old_val.b_val = 0;
            node_arr[num - 1].new_val.b_val = 0;
        }
        else if (node_arr[num - 1].type == 3)
        {
            node_arr[num - 1].old_val.c_val = 0;
            node_arr[num - 1].new_val.c_val = 0;
        }
        node_arr[num - 1].ret = 0;
        char *node = shared_to_char(&node_arr[num - 1]);
        printf("%s\n", node);
    }
    printf("modbus OK\n--------------%d\n", __LINE__);

    cJSON *cloudmedicinecabinet = cJSON_GetObjectItem(root, "cloudmedicinecabinet");
    cJSON *cdata = cJSON_GetObjectItem(cloudmedicinecabinet, "data");
    size = cJSON_GetArraySize(cdata);
    for (size_t i = 0; i < size; i++)
    {
        cJSON *tmp = cJSON_GetArrayItem(cdata, i);
        cJSON *key = cJSON_GetObjectItem(tmp, "key");
        cJSON *name = cJSON_GetObjectItem(tmp, "name");
        cJSON *type = cJSON_GetObjectItem(tmp, "type");

        num++;
        node_arr[num - 1].key = key->valueint;
        strcpy(node_arr[num - 1].name, name->valuestring);
        node_arr[num - 1].type = type->valueint;
        node_arr[num - 1].dev_type = 3;
        if (node_arr[num - 1].type == 1)
        {
            node_arr[num - 1].old_val.a_val = 0;
            node_arr[num - 1].new_val.a_val = 0;
        }
        else if (node_arr[num - 1].type == 2)
        {
            node_arr[num - 1].old_val.b_val = 0;
            node_arr[num - 1].new_val.b_val = 0;
        }
        else if (node_arr[num - 1].type == 3)
        {
            node_arr[num - 1].old_val.c_val = 0;
            node_arr[num - 1].new_val.c_val = 0;
        }
        node_arr[num - 1].ret = 0;
        char *node = shared_to_char(&node_arr[num - 1]);
        printf("%s\n", node);
    }
    printf("中药柜 OK\n--------------%d\n", __LINE__);
    *total = num;

    printf("点表初始化完成-------%d\n", __LINE__);
    free(buf);
    return 0;
}

//判断QT客户端发来的指令
int judge_device(char *buf)
{
    cJSON *root = cJSON_Parse(buf);
    if (NULL == root)
    {
        printf("judge_device parse err\n");
        return -1;
    }
    printf("%s\n", buf);
    cJSON *report = cJSON_GetObjectItem(root, "report");
    if (NULL != report)
    {
        cJSON *type = cJSON_GetObjectItem(report, "type");
        if (type->valueint == 0)
        {
            printf("接收到模式信号0---------------%d\n", __LINE__);
            send_mode = 0;
        }
        else if (type->valueint == 1)
        {
            printf("接收到模式信号1---------------%d\n", __LINE__);
            send_mode = 1;
        }
        else if (type->valueint == 2)
        {
            printf("接收到模式信号2---------------%d\n", __LINE__);
            send_mode = 2;
            cJSON *period = cJSON_GetObjectItem(report, "period");
            send_interval = period->valueint;
            printf("发送周期信号------------%d\n", __LINE__);
        }
    }

    cJSON *key = cJSON_GetObjectItem(root, "key");
    if (key != NULL)
    {
        if (key->valueint >= 0 && key->valueint <= 4)
        {
            return 1;
        }
        else if (key->valueint >= 5 && key->valueint <= 11)
        {
            return 2;
        }
        else if (key->valueint >= 12 && key->valueint <= 18)
        {
            return 3;
        }
        else if (key->valueint == 19)
        {
            return 1;
        }
    }
}

//线程函数
void *handler(void *arg)
{
    printf("线程创建成功\n---------%d\n", __LINE__);
    mqtt_client_to_server();
}

//序列化共享内存里的内容
char *shared_to_char(struct std_node *tmp)
{
    cJSON *root = cJSON_CreateObject();
    cJSON *key = cJSON_CreateNumber(tmp->key);
    cJSON_AddItemToObject(root, "key", key);
    cJSON *name = cJSON_CreateString(tmp->name);
    cJSON_AddItemToObject(root, "name", name);
    cJSON *type = cJSON_CreateNumber(tmp->type);
    cJSON_AddItemToObject(root, "type", type);
    cJSON *dev_type = cJSON_CreateNumber(tmp->dev_type);
    cJSON_AddItemToObject(root, "dev_type", dev_type);
    cJSON *val;
    if (type->valueint == 1)
    {
        int new_val = tmp->new_val.a_val;
        val = cJSON_CreateNumber(new_val);
    }
    else if (type->valueint == 2)
    {
        int new_val = tmp->new_val.b_val;
        val = cJSON_CreateNumber(new_val);
    }
    else if (type->valueint == 3)
    {
        float new_val = tmp->new_val.c_val;
        val = cJSON_CreateNumber(new_val);
    }
    cJSON_AddItemToObject(root, "val", val);

    char *buf = cJSON_PrintUnformatted(root);
    cJSON_Delete(root);
    return buf;
}

//上传共享内存里全部内容
void send_all_shared_memory()
{
    printf("mode值 = %d\n", send_mode);
    printf("上传共享内存里的全部内容\n-----------------%d\n", __LINE__);
    printf("total = %d\n", *total);
    for (int i = 0; i < *total; i++)
    {
        char *buf = shared_to_char(&node_arr[i]);
        pubmsg.payload = buf;
        pubmsg.payloadlen = (int)strlen(buf);
        pubmsg.qos = QOS;
        pubmsg.retained = 0;
        MQTTClient_publishMessage(client, TOPICUP, &pubmsg, &token);
    }
    if (node_arr[0].new_val.a_val == 0 && node_arr[1].new_val.a_val == 0 && node_arr[2].new_val.a_val == 0)
    {
        pubmsg.payload = closekongtiao;
        pubmsg.payloadlen = (int)strlen(closekongtiao);
        pubmsg.qos = QOS;
        pubmsg.retained = 0;
        MQTTClient_publishMessage(client, TOPICUP, &pubmsg, &token);
    }
}

//上传共享内存中变化内容
void send_variation_shared_memory()
{
    for (int i = 0; i < *total; i++)
    {
        if (node_arr[i].old_val.c_val != node_arr[i].new_val.c_val ||
            node_arr[i].old_val.b_val != node_arr[i].new_val.b_val ||
            node_arr[i].old_val.a_val != node_arr[i].new_val.a_val)
        {
            node_arr[i].old_val = node_arr[i].new_val;
            char *buf = shared_to_char(&node_arr[i]);
            pubmsg.payload = buf;
            pubmsg.payloadlen = (int)strlen(buf);
            pubmsg.qos = QOS;
            pubmsg.retained = 0;
            MQTTClient_publishMessage(client, TOPICUP, &pubmsg, &token);
        }
    }
    if (node_arr[0].new_val.a_val == 0 && node_arr[1].new_val.a_val == 0 && node_arr[2].new_val.a_val == 0)
    {
        pubmsg.payload = closekongtiao;
        pubmsg.payloadlen = (int)strlen(closekongtiao);
        pubmsg.qos = QOS;
        pubmsg.retained = 0;
        MQTTClient_publishMessage(client, TOPICUP, &pubmsg, &token);
    }
}

//根据上传方式上传共享内存内容
int send_shared_memory()
{
    if (send_mode == 0)
    {
        send_all_shared_memory();
        send_mode = -1;
    }
    else if (send_mode == 1)
    {
        while (send_mode == 1)
        {
            send_variation_shared_memory();
            sleep(1);
        }
    }
    else if (send_mode == 2)
    {
        while (send_mode == 2)
        {
            send_all_shared_memory();
            sleep(send_interval);
        }
    }

    return 0;
}